#pragma once
#include<iostream>
#include<vector>
#include<string>
#include<queue>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include"Thread.hpp"

// struct ThreadInfo
// {
//     pthread_t tid;
//     string name;
// };

static const int defaultnum=5;
template<class T>
class ThreadPool
{
public://默认函数、条件变量与互斥量的接口封装
 ThreadPool(int num=defaultnum):threads_(num)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&cond_,nullptr);
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
        //等待所有线程结束
        for(auto& thread:threads_){//回收正在运行的
            if(thread.IsRunning()) thread.Join();
        }
    }
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void Wakeup()
    {
        pthread_cond_signal(&cond_);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&cond_,&mutex_);
    }
    bool IsQueueEmpty()
    {
        return tasks_.empty();
    }
    string GetThreadName(pthread_t tid)
    {
        for( auto t:threads_)
        {
            if(t.Gettid()==tid) return t.Name();
        }
        return "None";
    }
    void Push(const T&in)//生产资源
    {
        Lock();
        tasks_.push(in);
        Wakeup();
        Unlock();
    }
    T Pop()//消费资源,由于Handler函数中加锁覆盖了Pop的整个生命周期所以不需要加锁这里
    {
        T t=tasks_.front();
        tasks_.pop();
        return t;
    }
    void Start()//创建并运行线程
    {
        int num=threads_.size();
        for(int i=0;i<num;i++)
        {
            //1.设置线程名称
            threads_[i].SetName("Thread-"+to_string(i));
            //2.绑定线程的任务处理函数,threads_ 中的 Thread 对象是默认构造的（未绑定任何入口函数）
            threads_[i]=Thread(HandlerTask,this);
            threads_[i].Run();
        }
    }
    static void *HandlerTask(void*args)
    {
        ThreadPool<T>*tp=static_cast<ThreadPool<T>*>(args);
        string name=tp->GetThreadName(pthread_self());
        while(true)
        {
            tp->Lock();
            //while循环防止误唤醒,线程在此处被唤醒后会重新判断条件是否成立
            while(tp->IsQueueEmpty()) tp->ThreadSleep();//代替Pop处理判空问题
            T t=tp->Pop();
            tp->Unlock();
            t();
            cout<<name<<" [run, "<<"result:"<<t.GetResult()<<endl;
        }
    }
private:
    vector<Thread> threads_;
    queue<T> tasks_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
    
};